using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Ltf.Remoting.TFAccess;
using Ltf.Diffs;
using Ltf.Remoting.RemoteEvents;
using System.IO;

namespace Ltf.MonitorLizard.Forms
{
	[FormType(FormTypes.ConflictResolver)]

	public partial class ThreeWayDiff : Form
	{
		private enum ViewType
		{
			full,
			merge
		}

		private enum ResolutionType
		{
			versionConflict,
			diffMerge
		}

		private ResolutionType resolutionType;

		private string repoPath;
		private string workspacePath;
		private int localBaseVersion;
		private int serverVersion;

		private string resultFile;

		private bool hasCommonBase;
		private ViewType viewType;
		private Control outputHost;

		public ThreeWayDiff()
		{
			InitializeComponent();
			outputHost = splitContainer2.Panel2;
			moOutput.ChangeRegionListBuilt += new EventHandler(moOutput_ChangeRegionListBuilt);
		}

		
		public ThreeWayDiff(string from, string to, string target)
			: this(from, to, target, target)
		{ }

		public ThreeWayDiff(string from, string to, string target, string resultFile)
			: this()
		{
			this.resultFile = resultFile;
				workspacePath = null;

				resolutionType = ResolutionType.diffMerge;

				string localFile = target;
				string baseFile = from;
				string serverFile = to;

				mergeView = false;
				tsbThreeWayVis.Checked = true;
				tsbMergeConflictView.Checked = false;
				CompareSideBySide(localFile, baseFile, serverFile, mergeView, true);

				moOutput.UserEditRegion += new UserEditRegionEventHandler(moOutput_UserSectionEdit);

		}

		void moOutput_UserSectionEdit(object sender, UserEditRegionEventArgs args)
		{
			StringBuilder yourLinesBdr = new StringBuilder();
			if (args.RegionToEdit.YourLines != null)
			{
				foreach (string yourLine in args.RegionToEdit.YourLines)
					yourLinesBdr.AppendLine(yourLine);
			}

			StringBuilder theirLinesBdr = new StringBuilder();
			if (args.RegionToEdit.TheirLines != null)
			{
				foreach (string theirLine in args.RegionToEdit.TheirLines)
					theirLinesBdr.AppendLine(theirLine);
			}

			StringBuilder mergeLines = new StringBuilder();
			if (args.RegionToEdit.MergedText != null)
			{
				foreach (string theirLine in args.RegionToEdit.MergedText)
					mergeLines.AppendLine(theirLine);
			}

			ChangeRegionEditor cre = new ChangeRegionEditor(yourLinesBdr.ToString(), theirLinesBdr.ToString(),Path.GetExtension(LocalFile));

			cre.EditLines = mergeLines.ToString();

			DialogResult dr = cre.ShowDialog();

			StringReader sr = new StringReader(cre.EditLines);
			List<string> editLines = new List<string>();
			string line;
			while ((line = sr.ReadLine()) != null)
				editLines.Add(line);

			args.RegionToEdit.EditText = editLines;

			args.Cancel = (dr == DialogResult.Cancel);
		}

		void moOutput_ChangeRegionListBuilt(object sender, EventArgs e)
		{
			tsslConflicts.Text = string.Format("Conflicts:{0}", moOutput.DiffDocument.NumberOfConflicts);
			tsslMerges.Text = string.Format("Merges:{0}", moOutput.DiffDocument.NumberOfMerges);
			tsslResolutions.Text = string.Format("Resolution:{0}", moOutput.DiffDocument.NumberOfResolutions);
			tsslUndoneMerges.Text = string.Format("Undone Merges:{0}", moOutput.DiffDocument.NumberOfUndoneMerges);
			tsbSave.Enabled = (moOutput.DiffDocument.NumberOfConflicts == 0);
		}

		private void twoWayDiff1_Load(object sender, EventArgs e)
		{

		}
		private string LocalFile, BaseFile, ServerFile;
		private string LocalFileFS, BaseFileFS, ServerFileFS;
		int contextLines = -1;


		public void SetUp(string localFile, string baseFile, string serverFile)
		{
			LocalFile = localFile;
			BaseFile = baseFile;
			ServerFile = serverFile;
		}

		bool ignoreRefresh = false;
		bool mergeView = false;

		public void CompareSideBySide(string localFile, string baseFile, string serverFile, bool mergeView, bool hasCommonBase)
		{
			viewType = mergeView ? ViewType.merge : ViewType.full;
			ignoreRefresh = true;
			this.hasCommonBase = hasCommonBase;
			this.mergeView = mergeView;
			SetUp(localFile, baseFile, serverFile);
			twoWayDiff1.SetCaptions(string.Format("Source:Base:{0}",serverFile), string.Format("Target:Base:{0}",localFile));

            LocalFileFS = localFile;
            BaseFileFS = baseFile;
            ServerFileFS = serverFile;

			Diff3Results d3r = twoWayDiff1.ShowDiff3(LocalFileFS, BaseFileFS, ServerFileFS, contextLines, mergeView, hasCommonBase);

			Ltf.Diffs.Diff3Docs.Output output;
			if (hasCommonBase)
			{
				output = new Ltf.Diffs.Diff3Docs.Output(LocalFileFS);
				output.LoadResults(d3r);
			}
			//			output = new Diff3CommonBaseDocument(LocalFileFS);
			else
				output = new Ltf.Diffs.Diff3Docs.Output(LocalFileFS);

	//		output.SetDiff3Output(d3r);

			moOutput.ShowOutput(output, d3r);
			ignoreRefresh = false;
		}

		public void ReshowSideBySide()
		{
			viewType = mergeView ? ViewType.merge : ViewType.full;
			ignoreRefresh = tsbIgnoreWhiteSpace.Checked;

			Diff3Results d3r = twoWayDiff1.ShowDiff3(LocalFileFS, BaseFileFS, ServerFileFS, contextLines, mergeView, hasCommonBase);

			ignoreRefresh = false;
		}


		private void tsbThreeWayVis_Click(object sender, EventArgs e)
		{
			ShowThreeWayVisualiser();
		}

		private void ShowThreeWayVisualiser()
		{
			viewType = ViewType.full;
			mergeView = false;
			tsbThreeWayVis.Checked = true;
			tsbMergeConflictView.Checked = false;
			ReshowSideBySide();
		}

		private void tsbMergeConflictView_Click(object sender, EventArgs e)
		{
			ShowMergeConflictView();
		}

		private void ShowMergeConflictView()
		{
			viewType = ViewType.merge;
			mergeView = true;
			tsbMergeConflictView.Checked = true;
			tsbThreeWayVis.Checked = false;
			ReshowSideBySide();
		}

		private void tsbHasCommonBase_Click(object sender, EventArgs e)
		{
			hasCommonBase = tsbHasCommonBase.Checked;
			if (viewType == ViewType.full)
				ShowThreeWayVisualiser();
			else
				ShowMergeConflictView();
		}

		private void tsbOutputAtSide_Click(object sender, EventArgs e)
		{
			if (outputHost != splitContainer2.Panel2)
			{
				Control oldHost = moOutput.Parent;
				splitContainer2.Panel2Collapsed = false;
				moOutput.Parent = splitContainer2.Panel2;
				splitContainer1.Panel2Collapsed = true;
				outputHost = splitContainer2.Panel2;
				if (oldHost.GetType() == typeof(ToolStripContentPanel))
					(oldHost.Parent.Parent as Form).Close();
			}
		}

		private void tsbOutputBeneath_Click(object sender, EventArgs e)
		{
			if (outputHost != splitContainer1.Panel2)
			{
				Control oldHost = moOutput.Parent;
				splitContainer1.Panel2Collapsed = false;
				moOutput.Parent = splitContainer1.Panel2;
				splitContainer2.Panel2Collapsed = true;
				outputHost = splitContainer1.Panel2;
				if (oldHost.GetType() == typeof(ToolStripContentPanel))
					(oldHost.Parent.Parent as Form).Close();
			}
		}

		private void tsbOutputInSeperateWindow_Click(object sender, EventArgs e)
		{
			if (outputHost == splitContainer1.Panel2 || outputHost == splitContainer2.Panel2)
			{
				MergedOutputForm f = new MergedOutputForm(twoWayDiff1, moOutput);
				f.Icon = this.Icon;
				f.Text = "LizardTF Merged Output";
				splitContainer1.Panel2Collapsed = true;
				splitContainer2.Panel2Collapsed = true;
				outputHost = f;
				f.Show();

			}
		}



		private void toolStripButton1_Click_1(object sender, EventArgs e)
		{
			twoWayDiff1.Next();
		}

		private void toolStripButton2_Click_1(object sender, EventArgs e)
		{
			twoWayDiff1.Previous();
		}

		private void tsbNextConflict_Click(object sender, EventArgs e)
		{
			moOutput.Next();
		}

		private void tsbPreviousConflict_Click(object sender, EventArgs e)
		{
			moOutput.Previous();
		}

		private void tsmShowXLines_Click(object sender, EventArgs e)
		{
			tsmShowAllLines.Checked = false;
			tsmShow3Lines.Checked = false;
			tsmShow5Lines.Checked = false;
			tsmShow7Lines.Checked = false;
			tsmShowCustomLines.Checked = false;

			ToolStripMenuItem tsmItem = (ToolStripMenuItem)sender;
			tsmItem.Checked = true;
			int cl;
			int.TryParse(tsmItem.Tag.ToString(), out cl);

			if (cl == -2)
				if (!int.TryParse(tstbContextLines.Text, out cl))
				{
					cl = 3;
					tstbContextLines.Text = "3";
				}

			if (cl != contextLines)
			{
				contextLines = cl;
				ReshowSideBySide();
			}

		}

		private void tsslConflicts_Click(object sender, EventArgs e)
		{
			
		}

		private void tsbContextLines_ButtonClick(object sender, EventArgs e)
		{

		}

		private void tsbReset_Click(object sender, EventArgs e)
		{
			DialogResult dr = MessageBox.Show("Do you wish to undo all resolutions and redo all merges?", "Diff/Merge Reset", MessageBoxButtons.YesNo,
				MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);
			if (dr == DialogResult.Yes)
				CompareSideBySide(LocalFile, BaseFile, ServerFile, mergeView, hasCommonBase);
		}

		private void tsbSave_Click(object sender, EventArgs e)
		{
			SaveMergeOutput();
		}

		private void SaveMergeOutput()
		{
			switch (resolutionType)
			{
				case ResolutionType.versionConflict:
                    throw new InvalidOperationException("TFS based operations no longer supported");
					break;
				case ResolutionType.diffMerge:
					SaveMergedFile();
					break;
			}
		}

		

		private void SaveMergedFile()
		{
			string saveFile = resultFile;
			// check out file
			if (File.Exists(saveFile))
			{
				if ((File.GetAttributes(saveFile) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
				{
					DialogResult dr = MessageBox.Show("The local working copy is read-only, overwrite anyway?",
						"Overwrite File?", MessageBoxButtons.OKCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);
					if (dr == DialogResult.Cancel)
						return;

					File.SetAttributes(saveFile, File.GetAttributes(workspacePath) ^ FileAttributes.ReadOnly);
				}
				//take a copy just in case
				string tempPreMergeCopy = Path.Combine(Path.GetTempPath(), Path.GetFileName(saveFile) + ".premergecopy");
				if (File.Exists(tempPreMergeCopy))
					File.Delete(tempPreMergeCopy);
				File.Copy(saveFile, tempPreMergeCopy);
				try
				{
					//force a get of the server version
					File.Delete(saveFile);
					File.WriteAllText(saveFile, moOutput.Text);
					this.Close();
				}
				catch (Exception ex)
				{
					File.Copy(tempPreMergeCopy, saveFile);
					MessageBox.Show(string.Format("Save failed with message:\r\n{0}", ex.Message));
				}
			}
			else
			{
				try
				{
					//force a get of the server version
					File.WriteAllText(saveFile, moOutput.Text);
					this.Close();
				}
				catch (Exception ex)
				{
					MessageBox.Show(string.Format("Save failed with message:\r\n{0}", ex.Message));
				}
			}
		}

		private void tsbFind_Click(object sender, EventArgs e)
		{
			if (twoWayDiff1.Focused)
				twoWayDiff1.FindNext(tsbTxtFind.Text);
			else if (moOutput.Focused && (outputHost == splitContainer1.Panel2 || outputHost == splitContainer2.Panel2))
				moOutput.FindNext(tsbTxtFind.Text);
		}

		private void tsbFindPrev_Click(object sender, EventArgs e)
		{
			if (twoWayDiff1.Focused)
				twoWayDiff1.FindPrevious(tsbTxtFind.Text);
			else if (moOutput.Focused && (outputHost == splitContainer1.Panel2 || outputHost == splitContainer2.Panel2))
				moOutput.FindPrevious(tsbTxtFind.Text);
		}

		private void tsbIgnoreWhiteSpace_Click(object sender, EventArgs e)
		{
			ReshowSideBySide();
		}
	}
}